 /*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is OntoLing.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2004.
 * All Rights Reserved.
 *
 * OntoLing was developed by the Artificial Intelligence Research Group
 * (ai-nlp.info.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about OntoLing can be obtained at 
 * http//ai-nlp.info.uniroma2.it/software/OntoLing.html
 *
 */

 /*
  * Contributor(s): Armando Stellato stellato@info.uniroma2.it
 */

/*
 * LinguisticSlotPanel.java
 *
 * Created on 13 maggio 2004, 17.56
 */

package it.uniroma2.art.ontoling.protege.ui;


import it.uniroma2.art.lw.manager.LinguisticWatermarkManager;
import it.uniroma2.art.lw.model.objects.SemIndexRetrievalException;
import it.uniroma2.art.lw.model.objects.SemanticIndex;
import it.uniroma2.art.lw.model.objects.ConceptualizedLR;
import it.uniroma2.art.lw.model.objects.LRWithGlosses;
import it.uniroma2.art.lw.model.objects.LinguisticInterface;
import it.uniroma2.art.lw.model.objects.TaxonomicalLR;
import it.uniroma2.art.ontoling.protege.OntoLingTab;
//import it.uniroma2.art.ontoling.protege.enrichment.Jena2Protege2JenaLinguisticEnricherWrapper;
import it.uniroma2.art.ontoling.protege.util.Util;

import java.awt.BorderLayout;
import java.awt.dnd.DnDConstants;
import java.awt.dnd.DragSource;
import java.awt.dnd.DropTarget;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JTree;
import javax.swing.tree.TreePath;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.stanford.smi.protege.model.Cls;
import edu.stanford.smi.protege.model.KnowledgeBase;
import edu.stanford.smi.protege.model.Project;
import edu.stanford.smi.protege.model.Slot;
import edu.stanford.smi.protege.resource.Colors;
import edu.stanford.smi.protege.resource.Icons;
import edu.stanford.smi.protege.resource.LocalizedText;
import edu.stanford.smi.protege.resource.ResourceKey;
import edu.stanford.smi.protege.ui.DisplayUtilities;
import edu.stanford.smi.protege.ui.HeaderComponent;
import edu.stanford.smi.protege.ui.SlotHierarchyRenderer;
import edu.stanford.smi.protege.ui.SlotSubslotRoot;
import edu.stanford.smi.protege.ui.SlotsTreeDragSourceListener;
import edu.stanford.smi.protege.ui.SlotsTreeFinder;
import edu.stanford.smi.protege.ui.SlotsTreeTarget;
import edu.stanford.smi.protege.util.CollectionUtilities;
import edu.stanford.smi.protege.util.ComponentFactory;
import edu.stanford.smi.protege.util.ComponentUtilities;
import edu.stanford.smi.protege.util.CreateAction;
import edu.stanford.smi.protege.util.DefaultRenderer;
import edu.stanford.smi.protege.util.DeleteAction;
import edu.stanford.smi.protege.util.LabeledComponent;
import edu.stanford.smi.protege.util.LazyTreeNode;
import edu.stanford.smi.protege.util.LazyTreeRoot;
import edu.stanford.smi.protege.util.ModalDialog;
import edu.stanford.smi.protege.util.SelectableContainer;
import edu.stanford.smi.protege.util.SelectableTree;
import edu.stanford.smi.protege.util.SuperslotTraverser;
import edu.stanford.smi.protege.util.TreePopupMenuMouseListener;
import edu.stanford.smi.protege.util.ViewAction;
import edu.stanford.smi.protege.util.WaitCursor;
//import edu.stanford.smi.protegex.owl.model.RDFResource;

/**
 * This component displays the superslot/subslot tree on OntologyPanel.
 *
 * @author Ray Fergerson <fergerson@smi.stanford.edu>
 * @author Armando Stellato <stellato@info.uniroma2.it>
 */
public class SubslotPane extends SelectableContainer  implements OntoLingOntoTree  {
    /**
     * 
     */
    private static final long serialVersionUID = 7201952249398040905L;
    private SetTerminologySlotPanel _setTerminologySlotPanel;
    private Project _project;
    private KnowledgeBase _knowledgeBase;
    private Action _createSlotAction;
    private Action _createSubslotAction;
    private Action _deleteSlotAction;
    private Action _viewSlotAction;
    private LabeledComponent _labeledComponent;
    private JPopupMenu ctxMenu;
    private GUI_Facade guiFacade;

    private final static int MAX_EXPANSIONS = 100;

    protected static Log logger = LogFactory.getLog(SubslotPane.class);
    
    public SubslotPane(Project p, SetTerminologySlotPanel setTerminologySlotPanel) {
        _setTerminologySlotPanel = setTerminologySlotPanel;
    	_project = p;
        _knowledgeBase = _project.getKnowledgeBase();
        _createSlotAction = getCreateAction();
        _deleteSlotAction = getDeleteAction();
        _createSubslotAction = getCreateSubslotAction();
        _viewSlotAction = getViewAction();
        guiFacade = OntoLingTab.getOntoLingTab().getGUIFacade();

        LazyTreeRoot root = createRoot(_knowledgeBase);
        SelectableTree tree = ComponentFactory.createSelectableTree(_viewSlotAction, root);
        tree.setCellRenderer(new SlotHierarchyRenderer());
        tree.setShowsRootHandles(true);
        tree.setSelectionRow(0);
        tree.setLargeModel(true);
        setSelectable(tree);
        setLayout(new BorderLayout());
        String slotHierarchyLabel = LocalizedText.getText(ResourceKey.SLOT_BROWSER_HIERARCHY_LABEL);
        _labeledComponent = new LabeledComponent(slotHierarchyLabel, ComponentFactory.createScrollPane(tree));
        _labeledComponent.setBorder(ComponentUtilities.getAlignBorder());
        addButtons(_labeledComponent);
//      add(createHeader(), BorderLayout.NORTH);
        add(_labeledComponent, BorderLayout.CENTER);
        add(new SlotsTreeFinder(_knowledgeBase, tree), BorderLayout.SOUTH);
        tree.addMouseListener(new TreePopupMenuMouseListener(tree) {
            public JPopupMenu getPopupMenu() {
                return SubslotPane.this.getPopupMenu();
            }
        });
        setupDragAndDrop();
        // Necessary because the actions don't get notified when the tree is initialized.
        _viewSlotAction.setEnabled(true);
        _deleteSlotAction.setEnabled(true);
    }
    
    public LabeledComponent getLabeledComponent() {
        return _labeledComponent;
    }
    
    private JComponent createHeader() {
        JLabel label = ComponentFactory.createLabel(Icons.getProjectIcon());
        label.setText(_project.getName());
        String slotBrowserLabel = LocalizedText.getText(ResourceKey.SLOT_BROWSER_TITLE);
        String forProjectLabel = LocalizedText.getText(ResourceKey.CLASS_BROWSER_FOR_PROJECT_LABEL);
        HeaderComponent header = new HeaderComponent(slotBrowserLabel, forProjectLabel, label);
        header.setColor(Colors.getSlotColor());
        return header;
    }

    protected LazyTreeRoot createRoot(KnowledgeBase kb) {
        return new SlotSubslotRoot(kb);
    }

    protected void addButtons(LabeledComponent c) {
        c.addHeaderButton(_viewSlotAction);
        c.addHeaderButton(_createSlotAction);
        c.addHeaderButton(_deleteSlotAction);
    }

    protected Action createCollapseAllAction() {
        return new AbstractAction("Collapse") {
            public void actionPerformed(ActionEvent event) {
                ComponentUtilities.fullSelectionCollapse(getTree());
            }
        };
    }

    protected Action createExpandAllAction() {
        return new AbstractAction("Expand") {
            public void actionPerformed(ActionEvent event) {
                ComponentUtilities.fullSelectionExpand(getTree(), MAX_EXPANSIONS);
            }
        };
    }

    public void extendSelection(Slot slot) {
        ComponentUtilities.extendSelection(getTree(), slot);
    }

    protected Action getChangeSlotMetaclassAction() {
        final Slot slot = (Slot) getSoleSelection();
        Cls rootMetaclass = _knowledgeBase.getRootSlotMetaCls();
        final Collection c = CollectionUtilities.createCollection(rootMetaclass);
        boolean hasMultipleMetaclasses = DisplayUtilities.hasMultipleConcreteClses(_knowledgeBase, c);

        Action action = new AbstractAction("Change slot metaclass...") {
            public void actionPerformed(ActionEvent event) {
                Cls metaclass = pickConcreteCls(c, "Select Slot Metaclass");
                if (metaclass != null && !metaclass.equals(slot.getDirectType())) {
                    slot.setDirectType(metaclass);
                }
            }
        };
        action.setEnabled(hasMultipleMetaclasses && slot.isEditable());
        return action;
    }

    protected Cls pickConcreteCls(Collection allowedClses, String text) {
        return DisplayUtilities.pickConcreteCls(this, _knowledgeBase, allowedClses, text);
    }

    protected Action getChangeSubslotSlotMetaclassAction() {
        final Slot slot = (Slot) getSoleSelection();
        Cls rootMetaclass = _knowledgeBase.getRootSlotMetaCls();
        Collection c = CollectionUtilities.createCollection(rootMetaclass);
        boolean hasMultipleMetaclasses = DisplayUtilities.hasMultipleConcreteClses(_knowledgeBase, c);

        Action action = new AbstractAction("Change slot metaclass of subslots") {
            public void actionPerformed(ActionEvent event) {
                Cls metaCls = slot.getDirectType();
                String text = "Change slot metaclass of all subslots of ";
                text += slot.getName();
                text += " to " + metaCls.getName();
                int result = ModalDialog.showMessageDialog(SubslotPane.this, text, ModalDialog.MODE_OK_CANCEL);
                if (result == ModalDialog.OPTION_OK) {
                    WaitCursor waitCursor = new WaitCursor(SubslotPane.this);
                    try {
                        slot.setDirectTypeOfSubslots(metaCls);
                    } finally {
                        waitCursor.hide();
                    }
                }
            }
        };
        boolean enabled = slot.isEditable() && hasMultipleMetaclasses && slot.getDirectSubslotCount() >= 1;
        action.setEnabled(enabled);
        return action;
    }

    protected Action getCreateAction() {
        return new CreateAction(ResourceKey.SLOT_CREATE) {
            public void onCreate() {
                Slot slot = _knowledgeBase.createSlot(null);
                setSelectedSlot(slot);
            }
        };
    }

    protected Action getCreateSlotWithSlotMetaclassAction() {
        AbstractAction action = new AbstractAction("Create subslot using slot metaclass...") {
            public void actionPerformed(ActionEvent event) {
                Cls rootMetaCls = _knowledgeBase.getRootSlotMetaCls();
                Collection roots = CollectionUtilities.createCollection(rootMetaCls);
                Cls metaCls = pickConcreteCls(roots, "Select Slot Metaclass");
                Collection parents = SubslotPane.this.getSelection();
                if (metaCls != null && !parents.isEmpty()) {
                    Slot slot = _knowledgeBase.createSlot(null, metaCls, parents, true);
                    extendSelection(slot);
                }
            }
        };
        boolean enabled = hasMultipleConcreteSlotMetaClses();
        action.setEnabled(enabled);
        return action;
    }

    protected Action getCreateSubslotAction() {
        return new CreateAction(ResourceKey.SLOT_CREATE_SUBSLOT) {
            public void onCreate() {
                // SystemUtilities.debugBreak();
                Collection superSlots = SubslotPane.this.getSelection();
                Slot firstSuperslot = (Slot) CollectionUtilities.getFirstItem(superSlots);
                if (firstSuperslot != null) {
                    _knowledgeBase.beginTransaction("Create subslot of " + superSlots);
                    Cls metaCls = firstSuperslot.getDirectType();
                    Slot slot = _knowledgeBase.createSlot(null, metaCls, superSlots, true);
                    createInverseSlot(slot, superSlots);
                    _knowledgeBase.endTransaction(true);
                    extendSelection(slot);
                }
            }
        };
    }

    private void createInverseSlot(Slot slot, Collection superslots) {
        Collection superInverses = new ArrayList();
        Cls metaCls = null;
        Iterator i = superslots.iterator();
        while (i.hasNext()) {
            Slot superslot = (Slot) i.next();
            Slot inverse = superslot.getInverseSlot();
            if (inverse != null) {
                superInverses.add(inverse);
                if (metaCls == null) {
                    metaCls = inverse.getDirectType();
                }
            }
        }
        if (!superInverses.isEmpty()) {
            Slot inverse = _knowledgeBase.createSlot("inverse_of_" + slot.getName(), metaCls, superInverses, true);
            slot.setInverseSlot(inverse);
        }
    }

    protected Action getDeleteAction() {
        return new DeleteAction(ResourceKey.SLOT_DELETE, this) {
            public void onDelete(Collection slots) {
                handleDelete(slots);
            }

            public void onSelectionChange() {
                Slot slot = (Slot) CollectionUtilities.getFirstItem(this.getSelection());
                if (slot != null) {
                    setAllowed(slot.isEditable());
                }
            }
        };
    }

    protected void handleDelete(Collection slots) {
        removeSelection();
        try {
            _knowledgeBase.beginTransaction("Delete slots " + slots);
            Iterator i = slots.iterator();
            while (i.hasNext()) {
                Slot slot = (Slot) i.next();
                _knowledgeBase.deleteSlot(slot);
            }
        } finally {
            _knowledgeBase.endTransaction(true);
        }
    }

    public Slot getDisplayParent() {
        Slot slot = null;
        TreePath childPath = getTree().getSelectionModel().getLeadSelectionPath();
        if (childPath != null) {
            TreePath path = childPath.getParentPath();
            LazyTreeNode node = (LazyTreeNode) path.getLastPathComponent();
            Object o = node.getUserObject();
            slot = (o instanceof Slot) ? (Slot) o : null;
        }
        return slot;
    }

    public JComponent getDropComponent() {
        return getTree();
    }

    public List getPath(Slot slot, List list) {
        list.add(0, slot);
        Slot superslot = (Slot) CollectionUtilities.getFirstItem(slot.getDirectSuperslots());
        if (superslot != null) {
            getPath(superslot, list);
        }
        return list;
    }

    public JPopupMenu getPopupMenu() {
        return ctxMenu;
    }
    
    public void setPopupMenu(JPopupMenu menu) {
        ctxMenu = menu;
    }
    
    public JPopupMenu createStdPopupMenu() {
        JPopupMenu menu = null;
        Collection selection = getSelection();
        if (selection.size() == 1) {            
            menu = new JPopupMenu();
            menu.add(_createSlotAction);
            menu.add(_createSubslotAction);
            menu.add(getCreateSlotWithSlotMetaclassAction());
            menu.add(_deleteSlotAction);
            menu.addSeparator();
            menu.add(getChangeSlotMetaclassAction());
            menu.add(getChangeSubslotSlotMetaclassAction());
            menu.addSeparator();
            menu.add(createExpandAllAction());
            menu.add(createCollapseAllAction());
            
            /*
            menu.addSeparator();
            menu.add(searchLinguisticResource());            
            menu.addSeparator();
            menu.add(addTerms());
            if (LR_Locator.getInstanceOfLinguisticInterface().hasGlosses())
                menu.add(addGloss());
            if (LR_Locator.getInstanceOfLinguisticInterface().isConceptualized())
                menu.add(addSenseIdToConcept());
            menu.addSeparator();
            menu.add(changeNameToSelectedTerm());
            menu.add(createSubResourceWithSelectedTermAsID());
            if (LR_Locator.getInstanceOfLinguisticInterface().isTaxonomical())
                menu.add(addSubSlotsUsingSubConceptsFromLinguisticResources()); 
            menu.addSeparator();
            menu.add(callLinguisticEnrichment());
            */
        }
        return menu;
    }

    
    public Action addTerms(String label) {        
        return new AbstractAction(label, Icons.getBlankIcon()) {
            private static final long serialVersionUID = -8370687444998482108L;

            public void actionPerformed(ActionEvent event) {
                final Slot slot = (Slot) getSoleSelection();
                guiFacade.notifiedFrameTermInsertion((edu.stanford.smi.protege.model.Frame)slot);
            }
        };
    }
    
    public Action addSenseIdToResource(String label) {
        return new AbstractAction(label) {
            private static final long serialVersionUID = 1L;

            public void actionPerformed(ActionEvent event) {
                final Slot slot = (Slot) getSoleSelection();
                guiFacade.notifiedFrameSenseIdInsertion((edu.stanford.smi.protege.model.Frame)slot);
            }
        };
    }    
    
    
    public Action addGloss(String label) {        
        return new AbstractAction(label, Icons.getBlankIcon()) {
            private static final long serialVersionUID = -2721275868614954946L;

            public void actionPerformed(ActionEvent event) {
                final Slot slot = (Slot) getSoleSelection();
                guiFacade.notifiedFrameGlossInsertion((edu.stanford.smi.protege.model.Frame)slot);
            }
        };
    }       
    
    /*
     * LING_ENRICH
     * 
    public Action callLinguisticEnrichment(String label){
    	return new AbstractAction(label,Icons.getBlankIcon()){
            private static final long serialVersionUID = -1395373258605379317L;

            public void actionPerformed(ActionEvent event) {
    			Slot slot = (Slot) getSoleSelection();
    			Jena2Protege2JenaLinguisticEnricherWrapper lenrDelegate = EnrichmentPanel.getInstanceOfLinguisticEnricherWrapper();
                if (lenrDelegate.isEnrichable((RDFResource)slot)) {
                    lenrDelegate.getLEnrDialog().getEnrichmentGUI().changeFrame((RDFResource)slot);
                    logger.debug("EnrDialog: " + lenrDelegate.getLEnrDialog());
                    logger.debug("EnrGUI: " + lenrDelegate.getLEnrDialog().getEnrichmentGUI());
                    logger.debug("\n\nHostingFrameGUI: " + lenrDelegate.getLEnrDialog().getEnrichmentGUI().getHostingFrame() + "\n\n");                
                    lenrDelegate.getLEnrDialog().getEnrichmentGUI().getHostingFrame().toFront();	
                }                
                else JOptionPane.showMessageDialog(getRootPane(), "sorry this resource has not been considered for enrichment!", "no enrichable resource", JOptionPane.INFORMATION_MESSAGE);
    		}
    	};
    }
    */
    
    public Action searchLinguisticResource(String label) {
        
        return new AbstractAction(label, Icons.getBlankIcon()) {
            private static final long serialVersionUID = -648289438696779243L;

            public void actionPerformed(ActionEvent event) {
                final Slot slot = (Slot) getSoleSelection();
                String slotName = slot.getName();
                if(slotName.indexOf("#") != -1)
                	slotName = slotName.substring(slotName.indexOf("#")+1);
				else if(slotName.indexOf(":") != -1)
					slotName = slotName.substring(slotName.indexOf(":")+1);
                guiFacade.setSearchFieldText(slotName);
                guiFacade.notifiedSearchField();
            }
        };
    }    

    public Action changeNameToSelectedTerm(String label) {        
        return new AbstractAction(label, Icons.getBlankIcon()) {
            private static final long serialVersionUID = 1L;

            public void actionPerformed(ActionEvent event) {
                final Slot slot = (Slot) getSoleSelection();
                String slotName = slot.getName();
                int lastPos = slotName.lastIndexOf("#"); // TODO check if this system works always
                String newSlotName = slotName.substring(0, lastPos)+guiFacade.getSelectedWord();
                slot.rename(newSlotName);
                //slot.rename(guiFacade.getSelectedWord());
            }
        };
    }       
    
    public Action createSubResourceWithSelectedTermAsID(String label) {
        return new AbstractAction(label, Icons.getBlankIcon()) {
            private static final long serialVersionUID = -1395373258605379317L;

            public void actionPerformed(ActionEvent event) {
                Collection<?> parents = getSelection();
                if (!parents.isEmpty()) {
                	Slot newSlot = _knowledgeBase.createSlot(null, null, parents, true);
                    String slotName = newSlot.getName();
                    int lastPos = slotName.lastIndexOf("testDatarange_Class");
                    String newSlotName = slotName.substring(0, lastPos)+guiFacade.getSelectedWord();
                    newSlot.rename(newSlotName);
	                //extendSelection(slot);
                }
                Slot newSlot = _knowledgeBase.createSlot(null, null, parents, true);
            }
        };
    }    


    //TODO this one COULD be moved to DynamicMeyhodsLibrary
    //TODO take depth of taxonomy exploration (and other info) from a future preference menu
    public Action addSubResourcesUsingSubConceptsFromLinguisticResources(String label) {
        return new AbstractAction(label) {
            private static final long serialVersionUID = -5049103252569464187L;

            public void actionPerformed(ActionEvent event) {       
                LinguisticInterface lint = LinguisticWatermarkManager.getSelectedInterface();
                SemanticIndex c;
                
                try {
                    c = ((ConceptualizedLR)lint).getConcept(guiFacade.getSelectedSemex());
                    Collection<?> senses = ((TaxonomicalLR)lint).getDirectDescendants(c);
                    Collection<?> parents = getSelection();
                    if (!parents.isEmpty()) {
                        Slot slot = null;
                        Iterator<?> iterator = senses.iterator();
                        String[] labels;
                        while (iterator.hasNext()) {
                            c = (SemanticIndex)iterator.next();
                            labels = ((ConceptualizedLR)lint).getConceptLexicals(c);
                            slot = Util.createSlotThroughLabels(_knowledgeBase, labels, parents);
                            guiFacade.notifiedFrameTermInsertion(slot, ((ConceptualizedLR)lint).getConceptLexicals(c));
                            if (lint.hasGlosses())
                                guiFacade.notifiedFrameGlossInsertion(slot, ((LRWithGlosses)lint).getConceptGloss(c));
                        }
                        //extendSelection(slot);
                    }    
                } catch (SemIndexRetrievalException e) {
                    guiFacade.showErrorMessage("lnguistic resource access error", "inconsistency between semex field and linguistic resource", e);
                }
            }
        };
    }      
    
    public JTree getTree() {
        return (JTree) getSelectable();
    }

    protected Action getViewAction() {
        return new ViewAction(ResourceKey.SLOT_VIEW, this) {
            public void onView(Object o) {
                _project.show((Slot) o);
            }
        };
    }

    private boolean hasMultipleConcreteSlotMetaClses() {
        int nConcrete = 0;
        Collection metaClses = _knowledgeBase.getRootSlotMetaCls().getSubclasses();
        Iterator i = metaClses.iterator();
        while (i.hasNext() && nConcrete < 2) {
            Cls cls = (Cls) i.next();
            if (cls.isConcrete()) {
                ++nConcrete;
            }
        }
        return nConcrete > 1;
    }

    public void removeSelection() {
        ComponentUtilities.removeSelection(getTree());
    }

    public void setExpandedSlot(Slot slot, boolean expanded) {
        ComponentUtilities.setExpanded(getTree(), getPath(slot, new LinkedList()), expanded);
    }

    public void setFinderComponent(JComponent c) {
        add(c, BorderLayout.SOUTH);
    }

    public void setRenderer(DefaultRenderer renderer) {
        getTree().setCellRenderer(renderer);
    }

    public void setSelectedSlot(Slot slot) {
        if (!getSelection().contains(slot)) {
            ComponentUtilities.setSelectedObjectPath(getTree(), getPath(slot, new LinkedList()));
        }
    }

    private void setupDragAndDrop() {
        DragSource.getDefaultDragSource().createDefaultDragGestureRecognizer(
            getTree(),
            DnDConstants.ACTION_COPY_OR_MOVE,
            new SlotsTreeDragSourceListener());
        new DropTarget(getTree(), DnDConstants.ACTION_COPY_OR_MOVE, new SlotsTreeTarget());
    }

    public void setDisplayParent(Slot slot) {
        ComponentUtilities.setDisplayParent(getTree(), slot, new SuperslotTraverser());
    }

    public String toString() {
        return "SubslotPane";
    }
    
    public String getSelectedProp(){
    	if(getSoleSelection() != null)
    		return ((Slot)getSoleSelection()).getName();
    	return null;
    }

}
